using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Reflection;

namespace WebServiceClientGenerator
{
    internal class MethodSignature
    {
        private static readonly IList<Parameter> _emptyParameters = new Parameter[0];
        private string _name;

        internal string Name
        {
            get { return _name; }
            //set
            //{
            //    CodeUtils.CheckNullSetter(value);
            //    _name = value;
            //}
        }

        private IList<Parameter> _parameters = _emptyParameters;

        internal IList<Parameter> Parameters
        {
            get { return _parameters; }
            //set
            //{
            //    CodeUtils.CheckNullSetter(value);
            //    _parameters = value;
            //}
        }

        public MethodSignature(MethodInfo method)
        {
            CodeUtils.CheckArgumentNull(method, "method");
            _name = method.Name;
            _returnType = method.ReturnType;
            ParameterInfo[] parameters = method.GetParameters();
            if (parameters.Length != 0)
            {
                _parameters = new Parameter[parameters.Length];
                for(int i = 0; i<parameters.Length; i++)
                {
                    _parameters[i] = new Parameter(parameters[i]);
                }
            }
        }

        private Type _returnType = typeof(void);

        internal Type ReturnType
        {
            get { return _returnType; }
            //set { _returnType = value ?? typeof(void); }
        }

        public override bool Equals(object obj)
        {
            return ReferenceEquals(this, obj) || Equals(obj as MethodSignature);
        }

        public bool Equals(MethodSignature another)
        {
            return another != null &&
                   another._name == _name &&
                   ListEquals(another._parameters, _parameters);
        }

        private static bool ListEquals<T>(IList<T> x, IList<T> y)
        {
            if (ReferenceEquals(x, y)) return true;
            if (x == null || y == null) return false;
            if (x.Count != y.Count) return false;
            IEnumerator<T> ix = x.GetEnumerator(), iy = y.GetEnumerator();
            while (ix.MoveNext() && iy.MoveNext())
            {
                if (!ix.Current.Equals(iy.Current)) return false;
            }
            return true;
        }

        private int? _hashCode;

        public override int GetHashCode()
        {
            if (!_hashCode.HasValue)
            {
                int hasCode = _name.GetHashCode();
                foreach (Parameter parameter in _parameters)
                {
                    hasCode ^= parameter.GetHashCode();
                }
                _hashCode = hasCode;
            }
            return _hashCode.Value;
        }

        //private string _toString;

        //public override string ToString()
        //{
        //    if (_toString==null)
        //    {
        //        StringBuilder sb = new StringBuilder(_name, _parameters.Count * 10 + _name.Length);
        //        sb.Append('(');
        //        bool isFirst = true;
        //        foreach (Parameter parameter in _parameters)
        //        {
        //            if (isFirst) isFirst = false;
        //            else sb.Append(',');
        //            sb.Append(parameter);
        //        }
        //        sb.Append(')');
        //        _toString = sb.ToString();
        //    }
        //    return _toString;
        //}

        internal class Parameter
        {
            private FieldDirection _fieldDirection = FieldDirection.In;

            internal FieldDirection FieldDirection
            {
                get { return _fieldDirection; }
                //set { _fieldDirection = value; }
            }

            private Type _type;

            internal Type Type
            {
                get { return _type; }
                //set { _type = value; }
            }

            private string _name;

            internal string Name
            {
                get { return _name; }
                //set { _name = value; }
            }

            private bool _isOptional = false;

            //internal bool IsOptional
            //{
            //    get { return _isOptional; }
            //    set { _isOptional = value; }
            //}

            //internal Parameter(Type type)
            //{
            //    CodeUtils.CheckArgumentNull(type, "type");
            //    _type = type;
            //}

            //internal Parameter(Type type, string name)
            //    : this(type)
            //{
            //    _name = name;
            //}

            internal Parameter(ParameterInfo parameter)
            {
                CodeUtils.CheckArgumentNull(parameter, "info");
                _type = parameter.ParameterType;
                if (_type.IsByRef) _type = _type.GetElementType();
                _isOptional = parameter.IsOptional;
                _fieldDirection = CodeUtils.DetermineParameterDirection(parameter);
                _name = parameter.Name;
            }

            public override bool Equals(object obj)
            {
                return ReferenceEquals(this, obj) || Equals(obj as Parameter);
            }

            public bool Equals(Parameter another)
            {
                return another != null &&
                       another._type == _type &&
                       another._fieldDirection == _fieldDirection &&
                       another._isOptional == _isOptional;
            }

            public override int GetHashCode()
            {
                return _type.GetHashCode() ^ _fieldDirection.GetHashCode() ^ _isOptional.GetHashCode();
            }

            //public override string ToString()
            //{
            //    StringBuilder sb = new StringBuilder();
            //    Type type = _type;
            //    if (_isOptional)
            //    {
            //        sb.Append("params ");
            //        _type = _type.GetElementType();
            //    }
            //    else if (_fieldDirection == FieldDirection.Out) sb.Append("out");
            //    else if (_fieldDirection == FieldDirection.Ref) sb.Append("ref");
            //    sb.Append(type.Namespace).Append('.').Append(type.Name);
            //    return sb.ToString();
            //}
        }
    }
}
